package com.xindian.android.base.livepushsdk;

import android.Manifest;
import android.app.Fragment;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.PermissionChecker;
import android.text.TextUtils;
import android.util.Log;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Toast;

import com.alibaba.livecloud.live.AlivcMediaFormat;
import com.alibaba.livecloud.live.AlivcMediaRecorder;
import com.alibaba.livecloud.live.AlivcMediaRecorderFactory;
import com.alibaba.livecloud.live.AlivcStatusCode;
import com.alibaba.livecloud.live.OnLiveRecordErrorListener;
import com.alibaba.livecloud.live.OnNetworkStatusListener;
import com.alibaba.livecloud.live.OnRecordStatusListener;
import com.xindian.android.base.livepushsdk.listener.OnStarLiveCallBack;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by liujianjiu on 16/9/27.
 * 推流页面,目前只能适配竖屏推流不能兼容横屏模式推流
 */
public class StarLiveFragment extends Fragment {
    public static final int OUTPUT_RESOLUTION_240P = AlivcMediaFormat.OUTPUT_RESOLUTION_240P;
    public static final int OUTPUT_RESOLUTION_360P = AlivcMediaFormat.OUTPUT_RESOLUTION_360P;
    public static final int OUTPUT_RESOLUTION_480P = AlivcMediaFormat.OUTPUT_RESOLUTION_480P;
    public static final int OUTPUT_RESOLUTION_540P = AlivcMediaFormat.OUTPUT_RESOLUTION_540P;
    public static final int OUTPUT_RESOLUTION_720P = AlivcMediaFormat.OUTPUT_RESOLUTION_720P;
    public static final int OUTPUT_RESOLUTION_1080P = AlivcMediaFormat.OUTPUT_RESOLUTION_1080P;

    private static final String TAG = "push";
    private final int WHAT_RECONNECT_RECORDER = 1;
    private final int INIT_TIME = 8000;

    public static final int PERMISSION_REQUEST_CODE = 1;

    private static final String[] PERMISSION_MANIFEST = {
            Manifest.permission.CAMERA,
            Manifest.permission.RECORD_AUDIO
    };

    //默认状态
    private boolean mIsBautyOn = true;
    private boolean mIsFrontCamera = true;
    private boolean mIsFlashOn = false;
    private long mDelayTime;
    private long mInTime;
    private String mPushUrl;

    private SurfaceView mSurfaceView;
    private AlivcMediaRecorder mMediaRecorder;
    private Surface mPreviewSurface;
    private Map<String, Object> mConfigure = new HashMap<>();
    private boolean isRecording = false;
    private int mPreviewWidth = 0;
    private int mPreviewHeight = 0;
    private boolean mIsResume = false;

    private GestureDetector mDetector;
    private ScaleGestureDetector mScaleDetector;

    private int mOutPutReSolution = OUTPUT_RESOLUTION_480P;
    private int mMaxVideoBite = 800000;

    /**
     * 设置推流配置参数
     *
     * @param outPutReSolution 输出流分辨率。可用值:OUTPUT_RESOLUTION_240P,OUTPUT_RESOLUTION_360P,OUTPUT_RESOLUTION_480P,OUTPUT_RESOLUTION_540P
     *                         OUTPUT_RESOLUTION_720P,OUTPUT_RESOLUTION_1080P
     *                         默认值:OUTPUT_RESOLUTION_480P
     * @param maxVideoBite     最高编码码率。默认值:800000
     */
    public void setPushAtrr(int outPutReSolution, int maxVideoBite) {
        this.mOutPutReSolution = outPutReSolution;
        this.mMaxVideoBite = maxVideoBite;
    }

    private OnStarLiveCallBack mCallBack;

    /**
     * 设置推流状态回调接口
     *
     * @param callBack 推流状态回调接口
     */
    public void setCallBack(OnStarLiveCallBack callBack) {
        this.mCallBack = callBack;
    }

    public StarLiveFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//        mFragmentStarLiveBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_star_live, container, false);

        View rootView = inflater.inflate(R.layout.fragment_star_live, null);
        mSurfaceView = (SurfaceView) rootView.findViewById(R.id.sfv_star_live);
        LinearLayout.LayoutParams ps = (LinearLayout.LayoutParams) mSurfaceView.getLayoutParams();
        ps.height = getResources().getDisplayMetrics().heightPixels;
        mSurfaceView.setLayoutParams(ps);

        init();
        if (mPushUrl!=null && !mPushUrl.equals("")) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    startRecorder(mPushUrl);
                }
            }, 1000);
        }
        return rootView;
    }

    private void init() {
        if (Build.VERSION.SDK_INT >= 23) {
            permissionCheck();
        }

        //采集
        mSurfaceView.getHolder().addCallback(_CameraSurfaceCallback);
        mSurfaceView.setOnTouchListener(mOnTouchListener);
        //对焦，缩放
        mDetector = new GestureDetector(mSurfaceView.getContext(), mGestureDetector);
        mScaleDetector = new ScaleGestureDetector(mSurfaceView.getContext(), mScaleGestureListener);
        //初始化MediaRecorder
        mMediaRecorder = AlivcMediaRecorderFactory.createMediaRecorder();
        mMediaRecorder.init(getActivity());
        mMediaRecorder.setOnRecordStatusListener(mRecordStatusListener);
        mMediaRecorder.setOnNetworkStatusListener(mOnNetworkStatusListener);
        mMediaRecorder.setOnRecordErrorListener(mOnErrorListener);
        //设置参数
        mConfigure.put(AlivcMediaFormat.KEY_CAMERA_FACING,
                mIsFrontCamera ? AlivcMediaFormat.CAMERA_FACING_FRONT : AlivcMediaFormat.CAMERA_FACING_BACK);
        mConfigure.put(AlivcMediaFormat.KEY_MAX_ZOOM_LEVEL, 3);
        mConfigure.put(AlivcMediaFormat.KEY_OUTPUT_RESOLUTION, mOutPutReSolution);
        mConfigure.put(AlivcMediaFormat.KEY_MAX_VIDEO_BITRATE, mMaxVideoBite);
        mConfigure.put(AlivcMediaFormat.KEY_DISPLAY_ROTATION, AlivcMediaFormat.DISPLAY_ROTATION_0);
        mConfigure.put(AlivcMediaFormat.KEY_EXPOSURE_COMPENSATION, -1);//曝光度
    }

    private void permissionCheck() {
        int permissionCheck = PackageManager.PERMISSION_GRANTED;
        for (String permission : PERMISSION_MANIFEST) {
            if (PermissionChecker.checkSelfPermission(getActivity(), permission)
                    != PackageManager.PERMISSION_GRANTED) {
                permissionCheck = PackageManager.PERMISSION_DENIED;
            }
        }
        if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(getActivity(), PERMISSION_MANIFEST, PERMISSION_REQUEST_CODE);
        }
    }

    private final SurfaceHolder.Callback _CameraSurfaceCallback = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            holder.setKeepScreenOn(true);
            mPreviewSurface = holder.getSurface();
            mMediaRecorder.prepare(mConfigure, mPreviewSurface);
            if (mIsBautyOn) {
                if ((int) mConfigure.get(AlivcMediaFormat.KEY_CAMERA_FACING) == AlivcMediaFormat.CAMERA_FACING_FRONT) {
                    mMediaRecorder.addFlag(AlivcMediaFormat.FLAG_BEAUTY_ON);
                }
            }
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            mMediaRecorder.setPreviewSize(width, height);
            mPreviewWidth = width;
            mPreviewHeight = height;
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            mPreviewSurface = null;
            mMediaRecorder.stopRecord();
            mMediaRecorder.reset();
        }
    };

    private View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            mDetector.onTouchEvent(motionEvent);
            mScaleDetector.onTouchEvent(motionEvent);
            return true;
        }
    };

    private OnRecordStatusListener mRecordStatusListener = new OnRecordStatusListener() {
        @Override
        public void onDeviceAttach() {
            mMediaRecorder.addFlag(AlivcMediaFormat.FLAG_AUTO_FOCUS_ON);
        }

        @Override
        public void onDeviceAttachFailed(int facing) {

        }

        @Override
        public void onSessionAttach() {
            if (!TextUtils.isEmpty(mPushUrl) && mIsResume) {
                startRecorder(mPushUrl);
            }
            mMediaRecorder.focusing(0.5f, 0.5f);
        }

        @Override
        public void onSessionDetach() {

        }

        @Override
        public void onDeviceDetach() {

        }

        @Override
        public void onIllegalOutputResolution() {
            Log.d(TAG, "selected illegal output resolution");
        }
    };

    private OnNetworkStatusListener mOnNetworkStatusListener = new OnNetworkStatusListener() {
        @Override
        public void onNetworkBusy() {
            Log.d(TAG, "==== on network busy ====");
            Toast.makeText(getActivity(), R.string.live_push_live_network_busy, Toast.LENGTH_SHORT).show();
            if (mCallBack != null) {
                mCallBack.onStarLiveNetworkChange(OnStarLiveCallBack.NetworkState.WEAK);
            }
        }

        @Override
        public void onNetworkFree() {
            Log.d(TAG, "===== on network free ====");
            if (mCallBack != null) {
                mCallBack.onStarLiveNetworkChange(OnStarLiveCallBack.NetworkState.NORMAL);
            }
        }

        @Override
        public void onConnectionStatusChange(int status) {
            switch (status) {
                case AlivcStatusCode.STATUS_CONNECTION_START:
                    Log.d(TAG, "Start live stream connection!");
                    break;
                case AlivcStatusCode.STATUS_CONNECTION_ESTABLISHED:
                    Log.d(TAG, "Live stream connection is established!");
                    if (mCallBack != null) {
                        mCallBack.onStarLiveNetworkChange(OnStarLiveCallBack.NetworkState.NORMAL);
                    }
                    mDelayTime = 0;
                    if (mCallBack != null) {
                        mCallBack.onStarLiveStart();
                    }
                    break;
                case AlivcStatusCode.STATUS_CONNECTION_CLOSED:
                    Log.d(TAG, "Live stream connection is closed!");
                    stopRecord();
                    break;
            }
        }

        @Override
        public boolean onNetworkReconnect() {
            Log.d(TAG, "Reconnect");
            return true;
        }
    };

    private OnLiveRecordErrorListener mOnErrorListener = new OnLiveRecordErrorListener() {
        @Override
        public void onError(int errorCode) {
            switch (errorCode) {
                case AlivcStatusCode.ERROR_SERVER_CLOSED_CONNECTION:
                case AlivcStatusCode.ERORR_OUT_OF_MEMORY:
                case AlivcStatusCode.ERROR_CONNECTION_TIMEOUT:
                case AlivcStatusCode.ERROR_BROKEN_PIPE:
                case AlivcStatusCode.ERROR_ILLEGAL_ARGUMENT:
                case AlivcStatusCode.ERROR_IO:
                case AlivcStatusCode.ERROR_NETWORK_UNREACHABLE:
                    Log.d(TAG, "Live stream connection error-->" + errorCode);
                    long currTime = System.currentTimeMillis();
                    if (mCallBack != null && currTime - mInTime > INIT_TIME) {
                        mCallBack.onStarLiveError();
                    }
                    if (errorCode == AlivcStatusCode.ERROR_CONNECTION_TIMEOUT && mCallBack != null) {
                        mCallBack.onStarLiveNetworkChange(OnStarLiveCallBack.NetworkState.NONE);
                    }
                    break;
                case AlivcStatusCode.ERROR_AUTH_FAILED:
                    stopRecord();
                    if (mCallBack != null) {
                        mCallBack.onAuthFailure();
                    }
                    break;
                default:
                    Log.d(TAG, "Unexpected status code-->" + errorCode);
                    currTime = System.currentTimeMillis();
                    if (mCallBack != null && currTime - mInTime > INIT_TIME) {
                        mCallBack.onStarLiveError();
                    }
                    break;
            }
        }
    };

    /**
     * 推流地址无效重新刷新
     */
    public synchronized void restartRecorder() {
        if (mMediaRecorder != null) {
            stopRecord();
            startRecorder(mPushUrl);
        }
    }

    private synchronized void startRecorder(final String url) {
        Log.d(TAG, "isRecording " + isRecording);
        if (isRecording || url==null) {
            return;
        }
        if (mPreviewSurface != null) {
            Log.d(TAG, "startRecord " + url);
            mMediaRecorder.prepare(mConfigure, mPreviewSurface);
            mMediaRecorder.startRecord(url);
            isRecording = true;
        }
    }

    private synchronized void stopRecord() {
        if (isRecording) {
            Log.d(TAG, "stopRecord");
            mMediaRecorder.stopRecord();
            mMediaRecorder.reset();
            isRecording = false;
        }
    }

    private GestureDetector.OnGestureListener mGestureDetector = new GestureDetector.OnGestureListener() {
        @Override
        public boolean onDown(MotionEvent motionEvent) {
            return false;
        }

        @Override
        public void onShowPress(MotionEvent motionEvent) {

        }

        @Override
        public boolean onSingleTapUp(MotionEvent motionEvent) {
            if (mPreviewWidth > 0 && mPreviewHeight > 0) {
                float x = motionEvent.getX() / mPreviewWidth;
                float y = motionEvent.getY() / mPreviewHeight;
                mMediaRecorder.focusing(x, y);

            }
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
            return false;
        }

        @Override
        public void onLongPress(MotionEvent motionEvent) {

        }

        @Override
        public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
            return false;
        }
    };

    private ScaleGestureDetector.OnScaleGestureListener mScaleGestureListener = new ScaleGestureDetector.OnScaleGestureListener() {
        @Override
        public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
            mMediaRecorder.setZoom(scaleGestureDetector.getScaleFactor());
            return true;
        }

        @Override
        public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
        }
    };

    public void setUrl(String url) {
        mPushUrl = url;
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.d(TAG, "onResume");
        mIsResume = true;
        mInTime = System.currentTimeMillis();
        startRecorder(mPushUrl);
    }

    @Override
    public void onPause() {
        super.onPause();
        mIsResume = false;
        Log.d(TAG, "onPause");
        stopRecord();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mMediaRecorder != null) {
            mMediaRecorder.release();
        }
    }


    /**
     * 停止推流
     */
    public void stopLive() {
        stopRecord();
    }

    /**
     * @return 是否前置
     */
    public boolean isFrontCamera() {
        Object value = mConfigure.get(AlivcMediaFormat.KEY_CAMERA_FACING);
        if (value != null) {
            return (int) mConfigure.get(AlivcMediaFormat.KEY_CAMERA_FACING) == AlivcMediaFormat.CAMERA_FACING_FRONT;
        }
        return true;
    }

    /**
     * 切换镜头
     *
     * @return 是否切换成功
     */
    public boolean changeCamera() {
        int currFacing = mMediaRecorder.switchCamera();
        if (currFacing == AlivcMediaFormat.CAMERA_FACING_FRONT) {
            Toast.makeText(getActivity(), getString(R.string.live_push_live_camera_front), Toast.LENGTH_SHORT).show();
            if (mIsBautyOn) {
                mMediaRecorder.addFlag(AlivcMediaFormat.FLAG_BEAUTY_ON);
            }
        } else {
            Toast.makeText(getActivity(), getString(R.string.live_push_live_camera_back), Toast.LENGTH_SHORT).show();
        }
        mConfigure.put(AlivcMediaFormat.KEY_CAMERA_FACING, currFacing);
        return true;
    }

    /**
     * 切换美颜
     */
    public void changeBeauty() {
        if (mIsBautyOn) {
            Toast.makeText(getActivity(), getString(R.string.live_push_live_beauty_closed), Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(getActivity(), getString(R.string.live_push_live_beauty_open), Toast.LENGTH_SHORT).show();
        }
        mIsBautyOn = !mIsBautyOn;
        if (mIsBautyOn) {
            mMediaRecorder.addFlag(AlivcMediaFormat.FLAG_BEAUTY_ON);
        } else {
            mMediaRecorder.removeFlag(AlivcMediaFormat.FLAG_BEAUTY_ON);
        }
    }

    /**
     * 切换闪关灯
     */
    public void changeFlashModel() {
        if (!isFrontCamera()) {
            if (mIsFlashOn) {
                Toast.makeText(getActivity(), getString(R.string.live_push_live_flash_closed), Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(getActivity(), getString(R.string.live_push_live_flash_open), Toast.LENGTH_SHORT).show();
            }
            mIsFlashOn = !mIsFlashOn;
            if (mIsFlashOn) {
                mMediaRecorder.addFlag(AlivcMediaFormat.FLAG_FLASH_MODE_ON);
            } else {
                mMediaRecorder.removeFlag(AlivcMediaFormat.FLAG_FLASH_MODE_ON);
            }
        }
    }

    public void onTouch(MotionEvent event) {
        mDetector.onTouchEvent(event);
        mScaleDetector.onTouchEvent(event);
    }
}